package yang.VirtualMachine.chapter9;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;

import yang.VirtualMachine.chapter11.asm.Account;
import yang.VirtualMachine.chapter9.classStruct.constantPool.PoolValue;

public final class ClassUtil {
	
	/**
	 * 桥接调用defineClass（受保护的，子类才可调用）
	 * @author xinxin
	 */
	private static class ClassLoaderSun extends ClassLoader {
		public Class<?> getClassByByte(String name, byte[] b, int off, int len) {
			return defineClass(name, b, off, len);
		}
	}
	
	/**
	 * 执行字节码的 指定位置方法（当前类定义的方法）
	 */
	public static void runClass(String className, byte[] code, int methodIndex) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException {
		ClassLoaderSun loader = new ClassLoaderSun();
		Class exampleClass = loader.getClassByByte(className, code, 0, code.length);
		exampleClass.getDeclaredMethods()[methodIndex].invoke(exampleClass.newInstance(), new Object[] {});
	}
	
	/**
	 * byte数组写入文件，不存在则创建文件
	 * @param bytes
	 * @param fileName
	 * @throws IOException
	 */
	public static void write2File(byte[] bytes, String fileName) throws IOException {
		File file = new File(fileName);
		if (!file.exists()) {
			file.createNewFile();
		}
		FileOutputStream out = new FileOutputStream(file);
		out.write(bytes);
		out.close();
	}
	
	/**
	 * 获得输入流
	 * @param fileName
	 * @return
	 * @throws FileNotFoundException
	 */
	public static InputStream getInputStream(String fileName) throws FileNotFoundException {
		File file  = new File(fileName);
		InputStream input = new FileInputStream(file);
		return input;
	}
	
	public static String getStrByStream(InputStream input, int length) throws IOException {
		byte[] bytes = new byte[length];
		input.read(bytes);
		return new String(bytes);
	}
	
	/**
	 * 获取length长度的数据
	 * @param input
	 * @param length
	 * @return
	 * @throws IOException 
	 */
	public static long getNumByStream(InputStream input, int length) throws IOException {
		byte[] bytes = new byte[length];
		input.read(bytes);
		return getNumByBytes(bytes);
	}
	
	public static long getNumByBytes(byte[] bytes) {
		Long l = 0L;
		for (byte b: bytes) {
			l = (l << 8) | (b & 0xFF);
		}
		return l;
	}
	
	public static void showClassBean(ClassBean bean) {
		int index = -1;
		for (PoolValue value: bean.constantPool) {
			index ++;
			if (index == 0) {
				System.out.println("第0项默认跳过");
				continue;
			}
			System.out.printf("index %d,Name %s,Value %s\n" , index 
					,value.getClass().getSimpleName().replace("Processer", ""), value.getValue());
		}
	}
	
}
